from django.db import transaction
from rest_framework.authentication import TokenAuthentication, BasicAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from api.conf import order_status
from api.serializers.pay_serializer import PaySerializer
from api.utils.pywxpay import WXPayUtil
from app.models import Order, ProductSpec


@api_view(['POST'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def pay(request: Request):
    serializer = PaySerializer(data=request.data)
    if serializer.is_valid():
        order = serializer.validated_data['order']
        if order.user != request.user or order.status != order_status.NOT_PAYED:
            raise ValidationError(detail=u'订单不正确')

        for product in order.products.all():
            if not product.spec.is_on_shell:  # 商品已下架
                order = Order.objects.select_for_update().get(id=order.id)
                order_products = order.products.all()
                specs = ProductSpec.objects.select_for_update().filter(id__in=order_products)
                for order_product in order_products:
                    for spec in specs:
                        if spec.id == order_product.spec_id:
                            spec.stock += order_product.amount
                            spec.save()
                order.status = order_status.SYSTEM_CANCEL
                order.save()
                raise ValidationError(detail=u'%s已下架' % product.spec)

        pay_method = serializer.validated_data['pay_method']

        with transaction.atomic():
            order.pay_method = pay_method
            order.status = order_status.NOT_SHIPPED  # 付款完成未发货
            order.save()

        return Response({'detail': u'支付成功'})
    else:
        raise ValidationError(serializer.errors)


def wxpay_notify(request: Request):
    WXPayUtil.xml2dict(request.body)
    pass
